#include <vector>
#include <unordered_map>

using namespace std;

// 最大人工岛
// 给你一个大小为 n * n 二进制矩阵 grid 。最多 只能将一格 0 变成 1 。
// 返回执行此操作后，grid 中最大的岛屿面积是多少？
// 岛屿 由一组上、下、左、右四个方向相连的 1 形成
// 测试链接 : https://leetcode.cn/problems/making-a-large-island/

class Solution 
{
private:
    int m, n;

    void dfs(vector<vector<int>>& grid, int i, int j, int id)
    {
        if(i < 0 || i >= m || j < 0 || j >= n || grid[i][j] != 1) return;

        grid[i][j] = id;
        dfs(grid, i - 1, j, id);
        dfs(grid, i + 1, j, id);
        dfs(grid, i, j - 1, id);
        dfs(grid, i, j + 1, id);
    }

public:
    int largestIsland(vector<vector<int>>& grid) 
    {
        m = grid.size(), n = grid[0].size();
        int id = 2; // 给岛屿进行编号
        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(grid[i][j] == 1)
                {
                    dfs(grid, i, j, id++);
                }
            }
        }

        int sizes[id]; // 统计每个陆地的大小
        memset(sizes, 0, sizeof(sizes));
        int ans = 0;
        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(grid[i][j] > 1)
                {
                    ans = max(ans, ++sizes[grid[i][j]]);
                }
            }
        }

        // 讨论所有的 0 变成 1，能带来的最大岛的大小
        bool visited[id];
        memset(visited, 0, sizeof(visited));
        int up, down, left, right, merge;
        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                // grid 中的 1 都被置为编号 id 了
                if(grid[i][j] == 0)
                {
					up = i > 0 ? grid[i - 1][j] : 0;
					down = i + 1 < n ? grid[i + 1][j] : 0;
					left = j > 0 ? grid[i][j - 1] : 0;
					right = j + 1 < m ? grid[i][j + 1] : 0;
                    visited[up] = true;
					merge = 1 + sizes[up]; // 将点 (i, j) 的 0 变成 1
					if (!visited[down]) 
                    {
						merge += sizes[down];
						visited[down] = true;
					}
					if (!visited[left]) 
                    {
						merge += sizes[left];
						visited[left] = true;
					}
					if (!visited[right]) 
                    {
						merge += sizes[right];
						visited[right] = true;
					}
					ans = max(ans, merge);
					visited[up] = false;
					visited[down] = false;
					visited[left] = false;
					visited[right] = false;
                }
            }
        }

        return ans;
    }
};


class Solution 
{
private:
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    int m, n, count;

    void dfs(vector<vector<int>>& grid, int i, int j, int mark)
    {
        // 该位置为海洋或者已经被访问过
        if(grid[i][j] == 0 || grid[i][j] != 1) return;

        grid[i][j] = mark; // 标记该位置所属的岛屿
        for(int k = 0; k < 4; ++k)
        {
            int x = i + dx[k];
            int y = j + dy[k];
            if(x >= 0 && x < m && y >= 0 && y < n && grid[x][y] == 1)
            {
                ++count;
                dfs(grid, x, y, mark);
            }
        }
    }

public:
    int largestIsland(vector<vector<int>>& grid) 
    {
        m = grid.size(), n = grid[0].size();
        int isAllGrid = true;
        int mark = 2; // 岛屿的编号
        unordered_map<int, int> hash; // 统计岛屿的大小

        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                if(grid[i][j] == 0) isAllGrid = false;
                else if(grid[i][j] == 1)
                {
                    count = 1;
                    dfs(grid, i, j, mark);
                    hash[mark] = count; // 记录该岛屿的面积
                    ++mark;
                }
            }
        }

        if(isAllGrid) return m * n; // 都是岛屿

        int ret = 0;
        unordered_set<int> visitedGrid; // 标记访问过的岛屿
        for(int i = 0; i < m; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                count = 1;
                visitedGrid.clear(); // 清空上一次连接过的岛屿
                if(grid[i][j] == 0)
                {
                    for(int k = 0; k < 4; ++k)
                    {
                        int x = i + dx[k];
                        int y = j + dy[k];
                        if(x >= 0 && x < m && y >= 0 && y < n && !visitedGrid.count(grid[x][y]))
                        {
                            // 把相邻的岛屿连接起来
                            count += hash[grid[x][y]];
                            visitedGrid.insert(grid[x][y]); // 标记该岛屿已经连接过
                        }
                    }
                }
                ret = max(ret, count);
            }
        }
        return ret;
    }
};